<!DOCTYPE html>
<html>
<!--
Copyright 2011 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<!--
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Closure Unit Tests - goog.ui.ModalPopup</title>
<script src="../base.js"></script>
<script>
  goog.require('goog.a11y.aria');
  goog.require('goog.a11y.aria.State');
  goog.require('goog.ui.ModalPopup');
  goog.require('goog.dispose');
  goog.require('goog.dom');
  goog.require('goog.events');
  goog.require('goog.events.EventTarget');
  goog.require('goog.fx.css3');
  goog.require('goog.string');
  goog.require('goog.style');
  goog.require('goog.ui.PopupBase.EventType');
  goog.require('goog.testing.MockClock');
  goog.require('goog.testing.jsunit');
</script>
</head>
<body>
<div id="main"></div>
<script>


var popup;
var main = /** @type {!Element}*/ (goog.dom.getElement('main'));
var mockClock;


function setUp() {
  mockClock = new goog.testing.MockClock(true);
}


function tearDown() {
  goog.dispose(popup);
  mockClock.dispose();
  goog.a11y.aria.removeState(main, goog.a11y.aria.State.HIDDEN);
}


function testDispose() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  goog.dispose(popup);
  assertNull(goog.dom.getElementByClass('goog-modalpopup-bg'));
  assertNull(goog.dom.getElementByClass('goog-modalpopup'));
  assertEquals(0, goog.dom.getElementsByTagNameAndClass('span').length);
}


function testRenderWithoutIframeMask() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  assertEquals(0, goog.dom.getElementsByTagNameAndClass(
      'iframe', 'goog-modalpopup-bg').length);

  var bg = goog.dom.getElementsByTagNameAndClass('div', 'goog-modalpopup-bg');
  assertEquals(1, bg.length);
  var content = goog.dom.getElementByClass('goog-modalpopup');
  assertNotNull(content);
  var tabCatcher = goog.dom.getElementsByTagNameAndClass('span');
  assertEquals(1, tabCatcher.length);

  assertTrue(goog.dom.compareNodeOrder(bg[0], content) < 0);
  assertTrue(goog.dom.compareNodeOrder(content, tabCatcher[0]) < 0);
  assertEquals('true', goog.a11y.aria.getState(
      popup.getElementStrict(), goog.a11y.aria.State.HIDDEN));
  assertTrue(goog.string.isEmptySafe(goog.a11y.aria.getState(
      main, goog.a11y.aria.State.HIDDEN)));
  popup.setVisible(true);
  assertTrue(goog.string.isEmptySafe(goog.a11y.aria.getState(
      popup.getElementStrict(), goog.a11y.aria.State.HIDDEN)));
  assertEquals('true', goog.a11y.aria.getState(
      main, goog.a11y.aria.State.HIDDEN));
}


function testRenderWithIframeMask() {
  popup = new goog.ui.ModalPopup(true);
  popup.render();

  var iframe = goog.dom.getElementsByTagNameAndClass(
      'iframe', 'goog-modalpopup-bg');
  assertEquals(1, iframe.length);
  var bg = goog.dom.getElementsByTagNameAndClass('div', 'goog-modalpopup-bg');
  assertEquals(1, bg.length);
  var content = goog.dom.getElementByClass('goog-modalpopup');
  assertNotNull(content);
  var tabCatcher = goog.dom.getElementsByTagNameAndClass('span');
  assertEquals(1, tabCatcher.length);

  assertTrue(goog.dom.compareNodeOrder(iframe[0], bg[0]) < 0);
  assertTrue(goog.dom.compareNodeOrder(bg[0], content) < 0);
  assertTrue(goog.dom.compareNodeOrder(content, tabCatcher[0]) < 0);
  assertEquals('true', goog.a11y.aria.getState(
      popup.getElementStrict(), goog.a11y.aria.State.HIDDEN));
  assertTrue(goog.string.isEmptySafe(goog.a11y.aria.getState(
      main, goog.a11y.aria.State.HIDDEN)));
  popup.setVisible(true);
  assertTrue(goog.string.isEmptySafe(goog.a11y.aria.getState(
      popup.getElementStrict(), goog.a11y.aria.State.HIDDEN)));
  assertEquals('true', goog.a11y.aria.getState(
      main, goog.a11y.aria.State.HIDDEN));
}


function testRenderDoesNotShowAnyElement() {
  popup = new goog.ui.ModalPopup(true);
  popup.render();

  var iframe = goog.dom.getElementsByTagNameAndClass(
      'iframe', 'goog-modalpopup-bg');
  assertFalse(goog.style.isElementShown(iframe[0]));
  var bg = goog.dom.getElementsByTagNameAndClass('div', 'goog-modalpopup-bg');
  assertFalse(goog.style.isElementShown(bg[0]));
  assertFalse(goog.style.isElementShown(
      goog.dom.getElementByClass('goog-modalpopup')));
  var tabCatcher = goog.dom.getElementsByTagNameAndClass('span');
  assertFalse(goog.style.isElementShown(tabCatcher[0]));
}


function testIframeOpacityIsSetToZero() {
  popup = new goog.ui.ModalPopup(true);
  popup.render();

  var iframe = goog.dom.getElementsByTagNameAndClass(
      'iframe', 'goog-modalpopup-bg')[0];
  assertEquals(0, goog.style.getOpacity(iframe));
}


function testEventFiredOnShow() {
  popup = new goog.ui.ModalPopup(true);
  popup.render();

  var beforeShowCallCount = 0;
  var beforeShowHandler = function() {
    beforeShowCallCount++;
  };
  var showCallCount = false;
  var showHandler = function() {
    assertEquals('BEFORE_SHOW is not dispatched before SHOW',
        1, beforeShowCallCount);
    showCallCount++;
  };

  goog.events.listen(
      popup, goog.ui.PopupBase.EventType.BEFORE_SHOW, beforeShowHandler);
  goog.events.listen(popup, goog.ui.PopupBase.EventType.SHOW, showHandler);

  popup.setVisible(true);

  assertEquals(1, beforeShowCallCount);
  assertEquals(1, showCallCount);
}


function testEventFiredOnHide() {
  popup = new goog.ui.ModalPopup(true);
  popup.render();
  popup.setVisible(true);

  var beforeHideCallCount = 0;
  var beforeHideHandler = function() {
    beforeHideCallCount++;
  };
  var hideCallCount = false;
  var hideHandler = function() {
    assertEquals('BEFORE_HIDE is not dispatched before HIDE',
        1, beforeHideCallCount);
    hideCallCount++;
  };

  goog.events.listen(
      popup, goog.ui.PopupBase.EventType.BEFORE_HIDE, beforeHideHandler);
  goog.events.listen(popup, goog.ui.PopupBase.EventType.HIDE, hideHandler);

  popup.setVisible(false);

  assertEquals(1, beforeHideCallCount);
  assertEquals(1, hideCallCount);
}


function testShowEventFiredWithNoTransition() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  var showHandlerCalled = false;
  goog.events.listen(popup, goog.ui.PopupBase.EventType.SHOW, function() {
    showHandlerCalled = true;
  });

  popup.setVisible(true);
  assertTrue(showHandlerCalled);
}

function testHideEventFiredWithNoTransition() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  var hideHandlerCalled = false;
  goog.events.listen(popup, goog.ui.PopupBase.EventType.HIDE, function() {
    hideHandlerCalled = true;
  });

  popup.setVisible(true);
  popup.setVisible(false);
  assertTrue(hideHandlerCalled);
}

function testTransitionsPlayedOnShow() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  var mockPopupShowTransition = new MockTransition();
  var mockPopupHideTransition = new MockTransition();
  var mockBgShowTransition = new MockTransition();
  var mockBgHideTransition = new MockTransition();

  var showHandlerCalled = false;
  goog.events.listen(popup, goog.ui.PopupBase.EventType.SHOW, function() {
    showHandlerCalled = true;
  });

  popup.setTransition(mockPopupShowTransition, mockPopupHideTransition,
      mockBgShowTransition, mockBgHideTransition);
  assertFalse(mockPopupShowTransition.wasPlayed);
  assertFalse(mockBgShowTransition.wasPlayed);

  popup.setVisible(true);
  assertTrue(mockPopupShowTransition.wasPlayed);
  assertTrue(mockBgShowTransition.wasPlayed);

  assertFalse(showHandlerCalled);
  mockPopupShowTransition.dispatchEvent(goog.fx.Transition.EventType.END);
  assertTrue(showHandlerCalled);
}


function testTransitionsPlayedOnHide() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  var mockPopupShowTransition = new MockTransition();
  var mockPopupHideTransition = new MockTransition();
  var mockBgShowTransition = new MockTransition();
  var mockBgHideTransition = new MockTransition();

  var hideHandlerCalled = false;
  goog.events.listen(popup, goog.ui.PopupBase.EventType.HIDE, function() {
    hideHandlerCalled = true;
  });

  popup.setTransition(mockPopupShowTransition, mockPopupHideTransition,
      mockBgShowTransition, mockBgHideTransition);
  popup.setVisible(true);
  assertFalse(mockPopupHideTransition.wasPlayed);
  assertFalse(mockBgHideTransition.wasPlayed);

  popup.setVisible(false);
  assertTrue(mockPopupHideTransition.wasPlayed);
  assertTrue(mockBgHideTransition.wasPlayed);

  assertFalse(hideHandlerCalled);
  mockPopupHideTransition.dispatchEvent(goog.fx.Transition.EventType.END);
  assertTrue(hideHandlerCalled);
}


function testTransitionsAndDisposingOnHideWorks() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  goog.events.listen(popup, goog.ui.PopupBase.EventType.HIDE, function() {
    popup.dispose();
  });

  var popupShowTransition = goog.fx.css3.fadeIn(popup.getElement(),
      0.1 /* duration */);
  var popupHideTransition = goog.fx.css3.fadeOut(popup.getElement(),
      0.1 /* duration */);
  var bgShowTransition = goog.fx.css3.fadeIn(popup.getElement(),
      0.1 /* duration */);
  var bgHideTransition = goog.fx.css3.fadeOut(popup.getElement(),
      0.1 /* duration */);

  popup.setTransition(popupShowTransition, popupHideTransition,
      bgShowTransition, bgHideTransition);
  popup.setVisible(true);
  popup.setVisible(false);
  // Nothing to assert. We only want to ensure that there is no error.
}


function testSetVisibleWorksCorrectlyWithTransitions() {
  popup = new goog.ui.ModalPopup();
  popup.render();
  popup.setTransition(
      goog.fx.css3.fadeIn(popup.getElement(), 1),
      goog.fx.css3.fadeIn(popup.getBackgroundElement(), 1),
      goog.fx.css3.fadeOut(popup.getElement(), 1),
      goog.fx.css3.fadeOut(popup.getBackgroundElement(), 1));

  // Consecutive calls to setVisible works without needing to wait for
  // transition to finish.
  popup.setVisible(true);
  assertTrue(popup.isVisible());
  popup.setVisible(false);
  assertFalse(popup.isVisible());
  mockClock.tick(1100);

  // Calling setVisible(true) immediately changed the state to visible.
  popup.setVisible(true);
  assertTrue(popup.isVisible());
  mockClock.tick(1100);

  // Consecutive calls to setVisible, in opposite order.
  popup.setVisible(false);
  popup.setVisible(true);
  assertTrue(popup.isVisible());
  mockClock.tick(1100);

  // Calling setVisible(false) immediately changed the state to not visible.
  popup.setVisible(false);
  assertFalse(popup.isVisible());
  mockClock.tick(1100);
}


function testTransitionsDisposed() {
  popup = new goog.ui.ModalPopup();
  popup.render();

  var transition = goog.fx.css3.fadeIn(popup.getElement(), 0.1 /* duration */);

  var hideHandlerCalled = false;
  goog.events.listen(popup, goog.ui.PopupBase.EventType.HIDE, function() {
    hideHandlerCalled = true;
  });

  popup.setTransition(transition, transition, transition, transition);
  popup.dispose();

  transition.dispatchEvent(goog.fx.Transition.EventType.END);
  assertFalse(hideHandlerCalled);
}


function testBackgroundHeight() {
  // Insert an absolutely-positioned element larger than the viewport.
  var viewportSize = goog.dom.getViewportSize();
  var w = viewportSize.width * 2;
  var h = viewportSize.height * 2;
  var dummy = goog.dom.createElement('div');
  dummy.style.position = 'absolute';
  goog.style.setSize(dummy, w, h);
  document.body.appendChild(dummy);

  try {
    popup = new goog.ui.ModalPopup();
    popup.render();
    popup.setVisible(true);

    var size = goog.style.getSize(popup.getBackgroundElement());
    assertTrue('Background element must cover the size of the content',
        size.width >= w && size.height >= h);
  } finally {
    goog.dom.removeNode(dummy);
  }
}


function testSetupBackwardTabWrapResetsFlagAfterTimeout() {
  popup.setupBackwardTabWrap();
  assertTrue('Backward tab wrap should be in progress',
      popup.backwardTabWrapInProgress_);
  mockClock.tick(1);
  assertFalse('Backward tab wrap flag should be reset after delay',
      popup.backwardTabWrapInProgress_);
}


/**
 * @implements {goog.fx.Transition}
 * @extends {goog.events.EventTarget}
 */
var MockTransition = function() {
  goog.base(this);
  this.wasPlayed = false;
};
goog.inherits(MockTransition, goog.events.EventTarget);


MockTransition.prototype.play = function() {
  this.wasPlayed = true;
}


MockTransition.prototype.stop = goog.nullFunction;

</script>
</body>
</html>
